package com.zz.utils;



import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.NodeTraversor;
import org.jsoup.select.NodeVisitor;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HtmlContentMatcher {

    /**
     * 匹配结果封装类
     */
    public static class MatchResult {
        private final String matchedText;
        private final Element container;
        private final int startOffset;
        private final int endOffset;

        public MatchResult(String matchedText, Element container, int startOffset, int endOffset) {
            this.matchedText = matchedText;
            this.container = container;
            this.startOffset = startOffset;
            this.endOffset = endOffset;
        }

        public String getHtmlSnippet() {
            return container.html();
        }

        public String getOuterHtml() {
            return container.outerHtml();
        }

        public String getMatchedText() {
            return matchedText;
        }
    }

    /**
     * 匹配规则接口
     */
    public interface MatchRule {
        boolean matches(String text);
    }

    /**
     * 正则表达式匹配规则
     */
    public static class RegexRule implements MatchRule {
        private final Pattern pattern;

        public RegexRule(String regex) {
            this.pattern = Pattern.compile(regex, Pattern.DOTALL);
        }

        @Override
        public boolean matches(String text) {
            return pattern.matcher(text).find();
        }
    }

    /**
     * 前缀后缀匹配规则
     */
    public static class SurroundRule implements MatchRule {
        private final String prefix;
        private final String suffix;

        public SurroundRule(String prefix, String suffix) {
            this.prefix = prefix;
            this.suffix = suffix;
        }

        @Override
        public boolean matches(String text) {
            return text.contains(prefix) && text.contains(suffix) &&
                    text.indexOf(prefix) < text.lastIndexOf(suffix);
        }
    }

    private final Document document;
    private final List<TextBlock> textBlocks = new ArrayList<>();

    public HtmlContentMatcher(String html) {
        this.document = Jsoup.parse(html);
        buildTextBlocks();
    }

    /**
     * 构建文本块索引
     */
    private void buildTextBlocks() {
        NodeTraversor.traverse(new NodeVisitor() {
            private Element currentContainer;
            private StringBuilder currentText = new StringBuilder();
            private int globalOffset = 0;

            @Override
            public void head(Node node, int depth) {
                if (node instanceof TextNode) {
                    TextNode textNode = (TextNode) node;
                    String text = textNode.getWholeText();

                    textBlocks.add(new TextBlock(
                            text,
                            textNode,
                            currentContainer,
                            globalOffset,
                            globalOffset + text.length()
                    ));

                    globalOffset += text.length();
                    currentText.append(text);
                } else if (node instanceof Element) {
                    currentContainer = (Element) node;
                }
            }

            @Override
            public void tail(Node node, int depth) {
                if (node instanceof Element && node == currentContainer) {
                    currentContainer = currentContainer.parent();
                }
            }
        }, document);
    }

    /**
     * 查找所有匹配项
     */
    public List<MatchResult> findAll(MatchRule rule) {
        List<MatchResult> results = new ArrayList<>();
        StringBuilder fullText = new StringBuilder();

        for (TextBlock block : textBlocks) {
            fullText.append(block.text);
        }

        String fullString = fullText.toString();
        if (rule instanceof RegexRule) {
            Matcher matcher = ((RegexRule) rule).pattern.matcher(fullString);
            while (matcher.find()) {
                results.add(buildResult(matcher.start(), matcher.end()));
            }
        } else if (rule instanceof SurroundRule) {
            SurroundRule sr = (SurroundRule) rule;
            int start = fullString.indexOf(sr.prefix);
            while (start != -1) {
                int end = fullString.indexOf(sr.suffix, start + sr.prefix.length());
                if (end != -1) {
                    results.add(buildResult(start, end + sr.suffix.length()));
                    start = fullString.indexOf(sr.prefix, end);
                } else {
                    break;
                }
            }
        }
        return results;
    }

    /**
     * 构建匹配结果
     */
    private MatchResult buildResult(int globalStart, int globalEnd) {
        Element commonAncestor = null;
        StringBuilder matchedText = new StringBuilder();

        for (TextBlock block : textBlocks) {
            if (block.globalEnd > globalStart && block.globalStart < globalEnd) {
                int start = Math.max(globalStart - block.globalStart, 0);
                int end = Math.min(globalEnd - block.globalStart, block.text.length());

                matchedText.append(block.text.substring(start, end));

                if (commonAncestor == null) {
                    commonAncestor = block.container;
                } else {
                    commonAncestor = findCommonAncestor(commonAncestor, block.container);
                }
            }
        }

        return new MatchResult(
                matchedText.toString(),
                commonAncestor != null ? commonAncestor : document.body(),
                globalStart,
                globalEnd
        );
    }

    /**
     * 查找最近公共祖先节点
     */
    private Element findCommonAncestor(Element a, Element b) {
        Element elemA = a;
        while (elemA != null) {
            Element elemB = b;
            while (elemB != null) {
                if (elemA == elemB) {
                    return elemA;
                }
                elemB = elemB.parent();
            }
            elemA = elemA.parent();
        }
        return document.body();
    }

    /**
     * 文本块封装类
     */
    private static class TextBlock {
        final String text;
        final TextNode textNode;
        final Element container;
        final int globalStart;
        final int globalEnd;

        TextBlock(String text, TextNode textNode, Element container,
                  int globalStart, int globalEnd) {
            this.text = text;
            this.textNode = textNode;
            this.container = container;
            this.globalStart = globalStart;
            this.globalEnd = globalEnd;
        }
    }

    // 使用示例
    public static void main(String[] args) {
        String html = "<div>Hello <span>World! This is a <b>test</b> example.</span></div>";

        HtmlContentMatcher matcher = new HtmlContentMatcher(html);

        // 使用正则表达式匹配
        List<MatchResult> regexResults = matcher.findAll(
                new RegexRule("test.*example")
        );

        // 使用前后缀匹配
        List<MatchResult> surroundResults = matcher.findAll(
                new SurroundRule("World", "example")
        );

        regexResults.forEach(result -> {
            System.out.println("Matched: " + result.getMatchedText());
            System.out.println("HTML snippet:\n" + result.getHtmlSnippet());
        });
    }
}